﻿/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Alexandre Croiseaux
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.gui.texts
{
	import flash.display.DisplayObjectContainer;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import marcel.core.Plugin;
	import marcel.debug.debugw;
	import marcel.utils.StringUtils;
	
	/**
	 * A textfield with resizing and styling helpers
	 * @author Alexandre Croiseaux
	 */
	public class CoreField extends TextField
	{
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Contructs a new CoreField instance. If the stageField parameter is specified, the created CoreField instance will copy all stageField properties,
		 * and then remove the stageField from the display list.
		 * The 'setResizeBehavior' is called once from the constructor with default parameters.
		 * @param	x		the textfield x position
		 * @param	y		the textfield y position
		 * @param	width		the textfield width
		 * @param	height		the textfield height
		 */
		public function CoreField(x:Number = 0, y:Number = 0, width:Number = 100, height:Number = 16)
		{
			this.width = width;
			this.height = height;
			this.x = x;
			this.y = y;
			selectable = false;
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Public methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Set the current corefield text by using xml data and css styling.
		 * @param	path 	the path of the text to display. Ex: ["main_xml", "home", "title"]. The first element must be the asset id. Tha @class attribute found in the xml node is used to set the text style.
		 * @param   replaceParams 	array or object of variables to replace in the returned text using the StringUtils.injectVars method.
		 * @param 	replacePattern to use for replacement. by default pattern match {([0-9a-zA-Z]+)}
		 * @see	marcel.utils.StringUtils.injectVars
		 * @see	marcel.display.gui.texts.setCSSStyle
		 */
		public function setLabel(pathOrNodeOrString:*, replaceParams:* = null, replacePattern:String = "{([0-9a-zA-Z]+)}"):void
		{
			try
			{
				var str:String = "";
				if (pathOrNodeOrString != null)
				{
					if (pathOrNodeOrString is String)
					{
						str = pathOrNodeOrString;
					}
					else
					{
						var xml:*;
						if ((pathOrNodeOrString is Array) && pathOrNodeOrString.length > 0)
						{
							xml = Plugin.plugin.assetManager.getXMLAsset(pathOrNodeOrString.shift());
							for (var i:uint = 0; i < pathOrNodeOrString.length; i++) xml = xml[pathOrNodeOrString[i]];
						}
						else xml = pathOrNodeOrString;
						
						str = xml.toString();
						var clazz:String = xml.attribute("class").toString();
						if (clazz && clazz.length > 0)
						{
							var extraObj:Object;
							if (xml.attributes().length() > 1)
							{
								extraObj = {};
								for each (var attr:XML in xml.attributes()) extraObj[attr.name().toString()] = attr.toString();
							}
							setCSSStyle(clazz, null, extraObj);
						}
					}
				}
				
				if (replaceParams) str = StringUtils.injectVars(str, replaceParams, replacePattern);
				htmlText = str;
				
			}
			catch (err : Error)
			{
				debugw("Unable to sel label (pathOrNodeOrString=" + pathOrNodeOrString + ") : " + err);
			}
		}
		
		/**
		 * Indicates how the textfield should resize when it's text property is filled.
		 * By default, the text aligns left, the width is fixed and the height changes automatically.
		 * @param	align		Indicates the alignment of the paragraph. Valid values are TextFormatAlign constants.
		 * @param	autoSize	Controls automatic sizing and alignment of text fields. Acceptable values for the TextFieldAutoSize constants.
		 * @param	wordWrap	A Boolean value that indicates whether the text field has word wrap. If true, a new text line is created when the text reaches the width af the textfield
		 * @param	multiline	Indicates whether the text field is a multiline text field.
		 */
		public function setResizeBehavior(align:String = "left"/*TextFormatAlign.LEFT*/, autoSize:String = "left"/*TextFieldAutoSize.LEFT*/, wordWrap:Boolean = true, multiline:Boolean = true):void
		{
			if (styleSheet == null)
			{
				var tf:TextFormat = getTextFormat();
				tf.align = align;
				defaultTextFormat = tf;
				setTextFormat(tf);
			}
			
			this.autoSize = autoSize;
			this.wordWrap = wordWrap;
			this.multiline = multiline;
		}
		
		/**
		 * Apply style from CSS to the current textfield
		 * @param	styleName	the style class name to find in registered css files
		 * @param	cssID	the specific css file id to search style class in
		 * @param	extraPropsObj	an optional key/value object to apply extra textfield/textformat properties. e.g. {align:"right"}
		 */
		public function setCSSStyle(styleName:String, cssID:String = null, extraPropsObj:Object = null):void
		{
			StylesManager.formatTextField(this, styleName, cssID, extraPropsObj);
		}
		
		/**
		 * Indicates the display style of the textfield. All parameters are optional.
		 * @param	fontName		The name of the font for text in this textfield, as a string.
		 * @param	size			The point size of text in this textfield.
		 * @param	color			Indicates the color of the text.
		 * @param	bold			Indicates whether the text is boldface.
		 * @param	italic			Indicates whether text in this text format is italicized.
		 * @param	embedFonts		Indicates whether to render by using embedded font outlines. If false, Flash Player renders the text field by using device fonts.
		 * @param	selectable		A Boolean value that indicates whether the text field is selectable.
		 * @param	antiAliasType		The type of anti-aliasing used for this text field. Use flash.text.AntiAliasType  constants for this property. You can control this setting only if the font is embedded (with the embedFonts property set to true)
		 * @param	css			The stylesheet css content to use with this textfield.
		 */
		public function setStyle(fontName:String = "Arial", size:Number = 12, color:Number = 0x000000, bold:Boolean = false, italic:Boolean = false, embedFonts:Boolean = true, selectable:Boolean = false, antiAliasType:String = "advanced"/*AntiAliasType.ADVANCED*/):void
		{
			var tf:TextFormat = getTextFormat();
			tf.font = fontName;
			tf.size = size;
			tf.bold = bold;
			tf.italic = italic;
			tf.color = color;
			if (styleSheet == null)
			{
				defaultTextFormat = tf;
				setTextFormat(tf);
			}
			this.embedFonts = embedFonts;
			this.selectable = selectable;
			this.antiAliasType = antiAliasType;
		}
		
		/**
		 * Sets the 'prop' property of the current textFormat to the specified 'value' and applies the changed textformat.
		 * @param	prop	a TextFormat property.
		 * @param	value	the value to set the property to.
		 */
		public function setTextFormatProperty(prop:String, value:*):void
		{
			var tf:TextFormat = getTextFormat();
			tf[prop] = value;
			setTextFormat(tf);
		}
		
		/**
		 * The type of the text field.
		 * Either one of the following TextFieldType constants: TextFieldType.DYNAMIC,
		 * which specifies a dynamic text field, which a user cannot edit, or TextFieldType.INPUT,
		 * which specifies an input text field, which a user can edit.
		 */
		override public function set type(value:String):void
		{
			super.type = value;
			if (type == TextFieldType.INPUT) selectable = true;
		}
		
		/**
		 * Controls automatic sizing and alignment of text fields.
		 * Acceptable values for the TextFieldAutoSize constants: TextFieldAutoSize.NONE (the default),
		 * TextFieldAutoSize.LEFT, TextFieldAutoSize.RIGHT, and TextFieldAutoSize.CENTER.
		
		 * Values "down" and "bottom" are also accepted. In this case, TextFieldAutoSize.LEFT is used and wordWrap and multiline properties are set to true.
		
		 * If autoSize is set to TextFieldAutoSize.NONE (the default) no resizing occurs.If autoSize is set to TextFieldAutoSize.LEFT, the text is
		 * treated as left-justified text, meaning that the left margin of the text field remains fixed and any
		 * resizing of a single line of the text field is on the right margin. If the text includes a line break
		 * (for example, "\n" or "\r"), the bottom is also resized to fit the next
		 * line of text. If wordWrap is also set to true, only the bottom
		 * of the text field is resized and the right side remains fixed.If autoSize is set to TextFieldAutoSize.RIGHT, the text is treated as
		 * right-justified text, meaning that the right margin of the text field remains fixed and any resizing
		 * of a single line of the text field is on the left margin. If the text includes a line break
		 * (for example, "\n" or "\r"), the bottom is also resized to fit the next
		 * line of text. If wordWrap is also set to true, only the bottom
		 * of the text field is resized and the left side remains fixed.If autoSize is set to TextFieldAutoSize.CENTER, the text is treated as
		 * center-justified text, meaning that any resizing of a single line of the text field is equally distributed
		 * to both the right and left margins. If the text includes a line break (for example, "\n" or
		 * "\r"), the bottom is also resized to fit the next line of text. If wordWrap is also
		 * set to true, only the bottom of the text field is resized and the left and
		 * right sides remain fixed.
		 */
		override public function set autoSize(value:String):void
		{
			if (value == "down" || value == "bottom")
			{
				value = TextFieldAutoSize.LEFT;
				wordWrap = true;
				multiline = true;
			}
			
			super.autoSize = value;
		}
		
		/**
		 * Constructs a new Corefield instance and place it in the specified container.
		 * @param	container	The container to put the textfield in.
		 * @param	pathOrNode 	the path of the text to display as an Array or an XMLNode. Ex: ["main_xml", "home", "title"] or my_xml.node1.node2. The @class attribute found in the xml node is used to set the text style.
		 * @param   replaceParams 	array or object of variables to replace in the returned text using the StringUtils.injectVars method.
		 * @param	x		the textfield x position
		 * @param	y		the textfield y position
		 * @param	width		the textfield width
		 * @param	height		the textfield height
		 * @see	marcel.utils.StringUtils.injectVars
		 * @return the newly created textfield
		 */
		public static function create(container:DisplayObjectContainer, pathOrNodeOrString:*, replaceParams:* = null, x:Number = 0, y:Number = 0, width:Number = 100, height:Number = 16):CoreField
		{
			var cf:CoreField = new CoreField(x, y, width, height);
			cf.setLabel(pathOrNodeOrString, replaceParams);
			if (container) container.addChild(cf);
			return cf;
		}
	}
	
}